# -*- coding: utf-8-*-
import re
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from aliyunsdkdysmsapi import SendSmsRequest
from aliyunsdkdysmsapi import QuerySendDetailsRequest
from aliyunsdkcore.client import AcsClient
import openerp.tools as tools
import uuid, logging
from aliyunsdkcore.profile import region_provider
_logger = logging.getLogger(__name__)
"""
短信业务调用接口示例 
Created on 2017-06-12
"""
# 注意：不要更改
REGION = "cn-hangzhou"
PRODUCT_NAME = "Dysmsapi"
DOMAIN = "dysmsapi.aliyuncs.com"

# ACCESS_KEY_ID/ACCESS_KEY_SECRET 根据实际申请的账号信息进行替换
ACCESS_KEY_ID = "LTAIEmApq2rpLZIU"
ACCESS_KEY_SECRET = "IzXlL4IHlDO0bLeU7Og8LTcVkpsHl3"
acs_client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION)
region_provider.add_endpoint(PRODUCT_NAME, REGION, DOMAIN)

"""
门店三个二级菜单顺序：上门自提、门店提货记录、财务统计 上门自提里面的菜单就一个：门店下单，这个上门自提的卡券兑换新建时的页面只要输入卡券号码和密码

，点击保存，系统验证卡券号码和密码是否正确、是否激活、是否没有被禁用，然后保存兑换记录，写入财务信息，增加这个门店的应付款，这里的应付金额应
该需要在产品表中增加一个“补助费用”字段来事先维护好，如果补助费用为0说明没有维护过，保存对话记录时抛出例外提示操作失败补助费用为0无法兑换
"""


class apply_delivery(osv.osv):
    _name = 'apply.delivery'
    _rec_name = 'copy_code'
    _inherit = ['mail.thread', 'ir.needaction_mixin','china.city.county']

    def send_sms_api(self, business_id, phone_numbers, sign_name, template_code, template_param=None):
        smsRequest = SendSmsRequest.SendSmsRequest()
        # 申请的短信模板编码,必填
        smsRequest.set_TemplateCode(template_code)
        # 短信模板变量参数
        if template_param is not None:
            smsRequest.set_TemplateParam(template_param)
        # 设置业务请求流水号，必填。
        smsRequest.set_OutId(business_id)
        # 短信签名
        smsRequest.set_SignName(sign_name);
        # 短信发送的号码列表，必填。
        smsRequest.set_PhoneNumbers(phone_numbers)
        # 调用短信发送接口，返回json
        smsResponse = acs_client.do_action_with_exception(smsRequest)
        # TODO 业务处理
        return smsResponse

    def query_send_detail(self, biz_id, phone_number, page_size, current_page, send_date):
        queryRequest = QuerySendDetailsRequest.QuerySendDetailsRequest()
        # 查询的手机号码
        queryRequest.set_PhoneNumber(phone_number)
        # 可选 - 流水号
        queryRequest.set_BizId(biz_id)
        # 必填 - 发送日期 支持30天内记录查询，格式yyyyMMdd
        queryRequest.set_SendDate(send_date)
        # 必填-当前页码从1开始计数
        queryRequest.set_CurrentPage(current_page)
        # 必填-页大小
        queryRequest.set_PageSize(page_size)

        # 调用短信记录查询接口，返回json
        queryResponse = acs_client.do_action_with_exception(queryRequest)

        # TODO 业务处理
        return queryResponse

    def send_sms(self, mobile_phone, send_msg):
        __business_id = uuid.uuid1()
        return_vals = eval(self.send_sms_api(__business_id, mobile_phone, "东方团购中心",
                                             "SMS_125016076", template_param=send_msg))
        if not return_vals.get('BizId', False):
            _logger.exception(return_vals)
        return return_vals.get('BizId', False)

    def init(self, cr):
        cr.execute("ALTER TABLE apply_delivery DROP CONSTRAINT if exists apply_delivery_code_apply_uniq");

    def on_change_ship(self, cr, uid, ids, shipping_type, shipping_code, context=None):
        ''' 输入了快递方式即认为已在送货中 '''
        # if shipping_type and (not shipping_code):
        #     raise osv.except_osv(u'警告',u'请填写快递单号')
        # if shipping_code and (not shipping_type):
        #     raise osv.except_osv(u'警告',u'请填写快递方式')
        if shipping_type or shipping_code:
            return {'value': {'is_shipping': True}}
        else:
            return {'value': {'is_shipping': False}}
        # 快递单号和快递方式，只要有一个输入，另外一个必填

    def on_change_code_password(self, cr, uid, ids, copy_code, password, context=None):
        ''' 将输入的卡券号码转为卡券记录的id，并验证是否可以提货,然后验证用户名和密码是否匹配 '''
        # 若券号未输入，直接报错
        if not copy_code:
            if not password:
                return {}
            return {'warning': {'title': u'错误', 'message': u'请先输入卡券显示号码'}}

        card_line_id = self.pool['product.card.line'].search(
            cr, SUPERUSER_ID, [('code', '=', copy_code)], context=context)
        if card_line_id:
            card_line_id = card_line_id[0]  # 取输入券号的第一个id，转成int型
        else:
            return {'warning': {'title': u'错误', 'message': u'卡券号码不存在！'},
                    'value': {'password': '', 'copy_code': "", }}
        card_line = self.pool['product.card.line'].browse(
            cr, SUPERUSER_ID, card_line_id, context=context)
        # 先验证券号，如果验证失败报错，并清空券号和密码
        warning_msg = ''
        if not card_line_id:
            return {'warning': {'title': u'错误', 'message': copy_code + u'卡券号不存在'},
                    'value': {'copy_code': "", 'password': ""}}
        if not card_line.is_enabled:
            return {'warning': {'title': u'错误', 'message': copy_code + u'卡券未被启用'},
                    'value': {'copy_code': "", 'password': ""}}
        if not card_line.is_active:
            return {'warning': {'title': u'错误', 'message': copy_code + u'卡券未被激活 \n '},
                    'value': {'copy_code': "", 'password': ""}}
        if card_line.is_exchanged:
            return {'warning': {'title': u'错误', 'message': copy_code + u'卡券已被兑换'},
                    'value': {'copy_code': "", 'password': ""}}

        # 如果输入了密码，验证是否与券号匹配
        order_card_id = self.pool.get('order.card').search(
            cr, SUPERUSER_ID, [('starting_number_copy', '<=', card_line.code), ('ending_number', '>=', card_line.code),('order_id','!=',False)], limit=1, order='shipped_date asc', context=context)
        shipped_date = False
        partner_id = None
        if order_card_id:
            # raise osv.except_osv(u'错误', u"卡券未售出过")
            order_card_obj = self.pool.get('order.card').browse(
                cr, SUPERUSER_ID, order_card_id, context=context)
            shipped_date = order_card_obj.shipped_date
            partner_id = order_card_obj.partner_id.id
        if password:
            # 只有管理员有密码表的读取权限
            if not self.pool['product.card.password'].search(cr, SUPERUSER_ID,
                                                             [('line_id', '=', card_line_id),
                                                              ('password', '=', password)],
                                                             context=context):
                return {'warning': {'title': u'错误', 'message': u"卡券号和密码不匹配"},
                        'value': {'password': ""}}
            # 只有券号和密码都输入了且匹配，才填充卡券id字段
            return {'value': {'code': card_line_id, 'product_name': card_line.product_id.name, 'fisrt_time_sale': shipped_date, 'partner_id': partner_id}}
        else:
            return {'value': {'product_name': card_line.product_id.name,  'fisrt_time_sale': shipped_date, 'partner_id': partner_id}}

    def create(self, cr, uid, vals, context=None):
        if not vals.get('code', False) and not vals.get('outer_order_ref'):
            raise osv.except_osv(u'错误', u"请先输入卡券显示号码")
        track_obj = self.pool.get('product.card.track')
        card_line = self.pool['product.card.line'].browse(
            cr, SUPERUSER_ID, vals.get('code'), context=context)
        apply_delivery_obj = self.search(cr, uid, [('code', '=', vals.get(
            'code')), ('is_canceled', '=', True)], context=context)
        if apply_delivery_obj:
            osv.osv.unlink(self, cr, SUPERUSER_ID,
                           apply_delivery_obj, context=context)
        # 如果是门店自提记录，并且勾选了【需要送货】，get_is_shipping表示客户到门店上门自提
        # if vals.get('is_need_delivery',False):
        #     get_is_shipping=False
        # else:
        if card_line and not card_line.is_exchanged:
            card_line.write({'is_exchanged': True})
            track_obj.create(cr, SUPERUSER_ID, {'card_line_id': card_line.id,
                                                'code': card_line.code,
                                                'changed_field': u'是否兑换',
                                                'old_value': u'未兑换',
                                                'new_value': u'已兑换',
                                                'operation_type': 'exchange',
                                                })
        else:
            if card_line and not vals.get('orign_apply_delivery_id', False):
                raise osv.except_osv(u'错误', u"卡券已被兑换")
        order_card_id = self.pool.get('order.card').search(
            cr, SUPERUSER_ID, [('starting_number_copy', '<=', card_line.code), ('ending_number', '>=', card_line.code)],
            limit=1, order='shipped_date asc', context=context)
        shipped_date = False
        if order_card_id:
            #    raise osv.except_osv(u'错误', u"卡券未售出过")
            order_card_obj = self.pool.get('order.card').browse(
                cr, SUPERUSER_ID, order_card_id, context=context)
            shipped_date = order_card_obj.shipped_date
        vals.update({'copy_code': card_line.code, 'fisrt_time_sale': shipped_date})
        return_val = super(apply_delivery, self).create(cr, uid, vals, context=context)
        #self.delivery_send_sms(cr, uid, return_val, context=context)
        return return_val

    def delivery_send_sms(self, cr, uid, ids, context=None):
        if isinstance(ids, int):
            ids = [ids]
        all_nums = len(ids)
        success_nums, ignore_num, fail_num = 0, 0, 0
        
        for delivery in self.browse(cr, uid, ids, context=context):
            if delivery.is_shipping and delivery.shipping_type and delivery.mobile_number and delivery.shipping_code\
                    and not delivery.sms_bizid and not delivery.shipping_type.is_fictitious and not delivery.is_canceled\
                    and not delivery.change_apply_delivery_ids and tools.config['is_production']:
                params = "{\"code\":\"%s\",\"expname\":\"%s\",\"expno\":\"%s\"}" % \
                         (delivery.copy_code, delivery.shipping_type.name, delivery.shipping_code)
                bizid = self.send_sms(delivery.mobile_number, params)
                if bizid:
                    delivery.write({'sms_bizid': bizid})
                    success_nums += 1
                else:
                    fail_num += 1
            else:
                ignore_num += 1
        return all_nums, success_nums, ignore_num, fail_num

    #如果已发货
    def write(self, cr, uid, ids, vals, context=None):
        # 如果已经分配门店并且门店已接受
        for apply in self.browse(cr, uid, ids, context=context):
            if apply.is_shipping and not vals.get('is_shipping', 'default_val'):
                raise osv.except_osv(u'警告', u'已经发货不能撤销，只能取消或者换货！')
        if vals.get('is_shipping'):
            self.pool.get('apply.import.wizard').automatic_outgonging(cr, uid, ids, context=context)
        res = super(apply_delivery, self).write(cr, uid, ids, vals, context)
        if not vals.get('sms_bizid', False):
            self.delivery_send_sms(cr, uid, ids, context=context)
        return res

    def check_phone(self, cr, uid, ids, context=None):
        '''验证手机号输入是都规范'''
        for apply_delivery in self.browse(cr, uid, ids, context=context):
            if apply_delivery.to_name:
                if apply_delivery.mobile_number or apply_delivery.phone_number:
                    p2 = re.compile('\d{11}')
                    if apply_delivery.mobile_number and (not p2.match(apply_delivery.mobile_number)):
                        return False
                    return True
                else:
                    return False
            else:
                return True

    def check_shipping_code(self, cr, uid, ids, context=None):
        for apply_delivery in self.browse(cr, uid, ids, context=context):
            apply_delivery_ids = self.search(cr, uid, [('shipping_code', '=',
                                                       apply_delivery.shipping_code)], context=context)
            if apply_delivery_ids and len(apply_delivery_ids) > 1 and apply_delivery.shipping_code:
                return False
            else:
                return True

    def export_data(self, cr, uid, ids, fields_to_export, raw_data=False, context=None):
        '''记录哪些记录已经导出过'''
        return super(apply_delivery, self).export_data(cr, SUPERUSER_ID, ids, fields_to_export, raw_data, context=context)

    # 取得快递详情html
    def _get_express_detail_html(self, cr, uid, ids, field_name=None, arg=None, context=None):
        res = dict.fromkeys(ids, '')
        for apply_delivery in self.browse(cr, uid, ids, context=context):
            if apply_delivery['shipping_type'] and apply_delivery['shipping_code']:
                express_type_name = apply_delivery['shipping_type']['name']
                express_type_com = apply_delivery[
                    'shipping_type']['description']
                html = """<div>
                            <table border="0" cellpadding="0" cellspacing="0" class="oe_form_group"><tr>
                            <td><span class="oe_form_field">快递类型:%s</span></td>
                            <td><span class="oe_form_field">快递单号:%s</span></td></tr></table>
                            <button class="btn btn-normal" onclick="query_express_detail(this)">查询物流详情</button>
                            <div id="express-delivery-detail" data-shipping-type="%s" data-shipping-code="%s"></div>
                        </div>""" % (express_type_name, apply_delivery['shipping_code'],
                                     express_type_com, apply_delivery['shipping_code'])
                #<img src="/web/static/src/img/throbber.gif" width="16" height="16"/>
                res[apply_delivery.id] = html
            else:
                res[apply_delivery.id] = u'未发货'
        return res

    # 重载openerp的复制功能,提醒用户使用“复制”按钮
    def copy(self, cr, uid, id, default=None, context=None):
        raise osv.except_osv(u'警告', u'该复制功能有错误，请点击界面上的“复制”按钮！')

    # 弹出delivery.copy.wizard窗口,替代原本的复制功能
    def copy_button(self, cr, uid, id, default=None, context=None):
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'delivery.copy.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'name': u'提货记录复制向导',
            'target': 'new',
            'context': {'delivery_id_copied': id},
        }

    _columns = {
        'code': fields.many2one('product.card.line', u'卡券', required=False, copy=False, select=True),
        'copy_code': fields.char(u'卡券显示号码', copy=False, select=True),
        # 怎么两个产品字段，这个product_id只在一个view上用过，是否应该删除？
        'product_id': fields.related('code', 'product_id', type='many2one', relation='product.product', select=True,
                                     string='卡券订单', readonly=True, store=True, copy=False),
        'product_name': fields.char(u'产品名称', copy=False),
        'address': fields.char(u'街道地址', size=64),
        'postal_code': fields.char(u'邮编', size=64),
        # 当此字段有变更下方有提示消息
        'to_name': fields.char(u'姓名', size=64, track_visibility='always'),
        'ship_memo': fields.text(u'送货备注'),
        'mobile_number': fields.char(u'手机号码 ', size=64, track_visibility='always'),
        'phone_number': fields.char(u'电话号码', size=64, track_visibility='always'),
        'estimated_ship_date': fields.date(u'期望发货日期', track_visibility='always', copy=False),
        'shipping_code': fields.char(u'快递单号', size=64, copy=False),
        'password': fields.char(u'卡券密码', size=64, copy=False),
        'is_shipping': fields.boolean(u'发货中', size=64, copy=False, track_visibility='always', select=True),
        'is_need_delivery': fields.boolean(u'快递送货', size=64, copy=False, select=True),
        'is_export': fields.boolean(u'是否已导出', copy=False, select=True),
        'openid': fields.char(u'微信账号openid', copy=False),
        'express_detail_html': fields.function(_get_express_detail_html, string=u'快递详情', type='html', method=True, readonly=True),
        'client_name': fields.char(string=u'渠道', copy=False),
        'subsidy': fields.float(string=u'产品补助费', copy=False),
        'is_canceled': fields.boolean(u'是否取消', copy=False, select=True),
        'fisrt_time_sale': fields.date(u'卡券销售时间'),
        'shipping_type': fields.many2one('express.type',u'快递方式'),
        'orign_apply_delivery_id': fields.many2one('apply.delivery', string=u'原提货记录', select=True,
                                                   help=u'如果这是一张换货记录则会有原提货记录（指向另外一条提货记录）,否则原提货为空'),
        'change_apply_delivery_ids': fields.one2many('apply.delivery', 'orign_apply_delivery_id', string=u'换货记录',
                                                     help=u'列出所有的这个个卡券的换货记录'),
        'outer_order_ref': fields.char(string=u'外部订单号', copy=False),
        'outer_shop_name': fields.char(string=u'外部商店名称', copy=False),
        'sms_bizid': fields.char(string='短信返回值')
    }
    _defaults = {
        'is_need_delivery': True,
    }
    def show_repeat_code(self, cr, uid, ids, context):
        shipping_code_list = []
        for delivery_row in self.browse(cr, uid, ids, context=context):
            shipping_code_list.append(delivery_row.shipping_code)
        return u'\n快递单号%s有重复!'%('、'.join(shipping_code_list))
    
    _constraints = [(check_phone, u'\n请输入正确的手机号码或者电话号码，两个不能都为空', [
                     'mobile_number', 'phone_number']),
                    (check_shipping_code, lambda self, *a, **kw: self.show_repeat_code(*a, **kw), [
                        'shipping_code'])
                    ]
    #存在换货的情况：换货新建的提货记录也要记录卡券订单的卡券号码，及相关信息
    # _sql_constraints = [
    #     ('code_apply_uniq', 'unique(copy_code)', '同一张卡券号只能有一个提货记录!')
    # ]

    def cancel_apply_delivery(self, cr, uid, ids, context=None):
        apply_delivery_obj = self.browse(cr, uid, ids, context=context)
        user_objs = self.pool.get('res.users').browse(
            cr, uid, uid, context=context)

        if apply_delivery_obj.is_shipping:
            raise osv.except_osv(u'错误', u"提货记录已分配给门店并且已发货，不可取消提货记录!")
        if apply_delivery_obj.is_export and not user_objs[0].has_group('dzx_ext.group_call_center'):
            raise osv.except_osv(u'错误', u"提货记录已导出, 不可取消提货记录!")

        self.write(cr, uid, ids, {'is_canceled': True}, context=context)
        card_line = self.pool['product.card.line'].browse(
            cr, SUPERUSER_ID, apply_delivery_obj.code.id, context=context)
        card_line.write({'is_exchanged': False})
        track_obj = self.pool.get('product.card.track')
        track_obj.create(cr, SUPERUSER_ID, {'card_line_id': card_line.id,
                                   'code': card_line.code,
                                   'changed_field': u'是否兑换',
                                   'old_value': u'已兑换',
                                   'new_value': u'未兑换',
                                   'operation_type': 'exchange',
                                   })
        return True

class delivery_copy_wizard(osv.osv_memory):
    _name = 'delivery.copy.wizard'

    # 按下“确认“按钮之后，将输入的卡券号、密码与需要复制的数据一起生成新的记录。
    def confirm_button(self, cr, uid, ids, context=None):
        # 从context中获取相关信息
        delivery_id = context['delivery_id_copied'][0]
        # 获取除了卡号和密码之外的数据
        copy_data = self.pool.get('apply.delivery').copy_data(
            cr, uid, delivery_id, default=None, context=context)
        apply_deliverys = self.pool.get('apply.delivery').browse(
            cr, uid, delivery_id, context=context)[0]

        new_id = []
        wizard_obj = self.browse(cr, uid, ids, context=context)
        if wizard_obj[0].delivery_record:
            for line in wizard_obj[0].delivery_record:
                tmp = copy_data.copy()
                card_line_ids = self.pool['product.card.line'].search(
                    cr, SUPERUSER_ID, [('code', '=', line.copy_code)], context=context)
                data = dict({'code': card_line_ids[
                            0], 'copy_code': line.copy_code, "is_need_delivery": True}, **tmp)
                new_id.append(self.pool.get(
                    'apply.delivery').create(cr, uid, data, context))
            return {
                'type': 'ir.actions.act_window',
                'res_model': 'apply.delivery',
                'view_mode': 'tree,form',
                'view_type': 'form',
                'domain': "[('id','in',[" + ','.join(map(str, new_id)) + "])]",
            }

    _columns = {
        'delivery_record': fields.one2many('delivery.copy.line', 'name', required=False, help=u'对应向导记录明细'),
    }
# 提货记录复制向导的明细

class delivery_copy_line(osv.osv_memory):
    _name = 'delivery.copy.line'

    def on_change_value(self, cr, uid, ids, copy_code, password, context=None):
        if copy_code:
            if not self.pool.get('apply.delivery').search(cr, uid, [('copy_code', '=', copy_code), ('is_canceled', '=', False)], context=context):
                res = self.pool.get('apply.delivery').on_change_code_password(
                    cr, uid, ids, copy_code, password, context=context)
                return res
            else:
                return {'warning': {'title': u'错误', 'message': u'同一张卡券号只能有一个提货记录'}}

    _columns = {
        'name': fields.many2one('delivery.copy.wizard'),
        #'code':fields.many2one('product.card.line',u'卡券',required=False),
        'copy_code': fields.char(u'卡券号码', required=True),
        'password': fields.char(u'卡券密码', size=64, required=True),
    }

class express_type(osv.osv):
    """
    新建，添加，修改，快递方式
    """
    _name = 'express.type'
    _rec_name = 'name'
    _columns = {
        'name': fields.char(u'快递方式', size=64, required=True),
        'is_fictitious': fields.boolean(u'是否虚拟快递'),
        'description': fields.char(u'代码', size=64),
    }
